package com.lagou.edu.filter;

import com.google.common.collect.Lists;
import com.lagou.edu.pojo.MethodExecuteRecord;
import com.lagou.edu.service.DemoService;
import com.lagou.edu.utils.IpRecordUtil;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Activate(group = CommonConstants.CONSUMER)
public class TPMonitorFilter implements Filter, Runnable {

    Logger logger = LoggerFactory.getLogger(TPMonitorFilter.class);

    private final static Map<String, List<MethodExecuteRecord>> METHOD_RECORD_MAP = new HashMap<>();

    public TPMonitorFilter() {
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay((Runnable) this, 10, 5, TimeUnit.SECONDS);

        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(() -> {
            long now = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(60);
            METHOD_RECORD_MAP.forEach((key, value) -> value.removeIf(item -> item.getEndTime() < now));
        }, 60, 60, TimeUnit.SECONDS);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        String methodName = invocation.getMethodName();
        Long startTime = System.currentTimeMillis();
        Result invoke = invoker.invoke(invocation);
        Long endTime = System.currentTimeMillis();
        List<MethodExecuteRecord> list = METHOD_RECORD_MAP.getOrDefault(methodName, Collections.synchronizedList(Lists.newArrayList()));
        MethodExecuteRecord methodExecuteRecord = new MethodExecuteRecord();
        methodExecuteRecord.setDuration(endTime - startTime);
        methodExecuteRecord.setStartTime(startTime);
        methodExecuteRecord.setEndTime(endTime);
        list.add(methodExecuteRecord);
        METHOD_RECORD_MAP.put(methodName, list);
        return invoke;
    }

    @Override
    public void run() {
        METHOD_RECORD_MAP.forEach((key, value) -> {
            List<Long> durationList = new ArrayList<>();
            for (MethodExecuteRecord methodExecuteRecord : value) {
                if (methodExecuteRecord.getEndTime() < System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(60)) {
                    value.remove(methodExecuteRecord);
                } else {
                    durationList.add(methodExecuteRecord.getDuration());
                }
            }
            List<Long> collect = durationList.stream().sorted().collect(Collectors.toList());
//            System.out.println(collect);
            int size = collect.size();
            Long tp90 = collect.get((int) Math.floor(size * 0.9));
            Long tp99 = collect.get((int) Math.floor(size * 0.99));
            System.out.println("方法[" + key + "] ==> tp90:" + tp90 + "ms,tp99:" + tp99 + "ms");
        });
    }
}
